class tracer:
    def __init__(self, func):
        print('in tracer.__init__')
        self.calls = 0
        self.func = func

    def __call__(self, *args, **kwargs):
        self.calls += 1
        print('call %s to %s' % (self.calls, self.func.__name__))
        print(self)
        return self.func(*args, **kwargs)

    def __get__(self, instance, owner):
        print('in __get__')
        return wrapper(self, instance)


class wrapper:
    def __init__(self, desc, subj):
        print('in wrapper init')
        self.desc = desc
        self.subj = subj

    def __call__(self, *args, **kwargs):
        print('in wrapper call')
        return self.desc(self.subj, *args, **kwargs)


@tracer
def spam(a, b, c):
    print(a + b + c)


@tracer
def eggs(x, y):
    print(x ** y)


# spam(1, 23, 3)
# spam(a=4, b=4, c=34)
# eggs(2, 16)
# eggs(2, y=4)


class Person:
    def __init__(self, name, pay):
        self.name = name
        self.pay = pay

    @tracer
    def giveRaise(self, percent):
        self.pay *= (1.0 + percent)

    @tracer
    def lastName(self):
        print(self.name.split()[-1])
        return self.name.split()[-1]


print('methods...')
bob = Person('Bob Smith', 50000)
sue = Person('Sue Jones', 100000)
print(bob.name, sue.name)
sue.giveRaise(.10)
print(int(sue.pay))
print(bob.lastName(), sue.lastName())
